home *** CD-ROM | disk | FTP | other *** search
/ The Utilities Experience / The Utilities Experience - Volume 1.iso / software / misc / o-z / x-windows / mesa-amiwin / src / xmesa1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-03  |  27.8 KB  |  1,038 lines

  1. /* $Id: xmesa1.c,v 1.8 1995/11/30 00:52:30 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  1.2
  6.  * Copyright (C) 1995  Brian Paul  (brianp@ssec.wisc.edu)
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Library General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Library General Public
  19.  * License along with this library; if not, write to the Free
  20.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23.  
  24. /*
  25. $Log: xmesa1.c,v $
  26.  * Revision 1.8  1995/11/30  00:52:30  brianp
  27.  * fixed a few type warnings for Sun compiler
  28.  *
  29.  * Revision 1.7  1995/11/30  00:20:56  brianp
  30.  * added new PF_GRAYSCALE mode
  31.  *
  32.  * Revision 1.6  1995/11/08  22:08:50  brianp
  33.  * added 8-bit TrueColor dithering
  34.  *
  35.  * Revision 1.5  1995/11/03  17:41:48  brianp
  36.  * removed unused vars, fixed code for C++ compilation
  37.  *
  38.  * Revision 1.4  1995/11/01  15:14:03  brianp
  39.  * renamed all class variables per Steven Spitz
  40.  *
  41.  * Revision 1.3  1995/10/30  15:13:01  brianp
  42.  * replaced Current variable with XMesa
  43.  *
  44.  * Revision 1.2  1995/10/19  15:53:20  brianp
  45.  * new arguments to gl_new_context()
  46.  *
  47.  * Revision 1.1  1995/10/17  21:36:55  brianp
  48.  * Initial revision
  49.  *
  50.  */
  51.  
  52.  
  53.  
  54. /*
  55.  * Mesa/X11 interface, part 1.
  56.  *
  57.  * This file contains the implementations of all the XMesa* functions.
  58.  *
  59.  *
  60.  * NOTES:
  61.  *
  62.  * The window coordinate system origin (0,0) is in the lower-left corner
  63.  * of the window.  X11's window coordinate origin is in the upper-left
  64.  * corner of the window.  Therefore, most drawing functions in this
  65.  * file have to flip Y coordinates.
  66.  *
  67.  * Define SHM in the Makefile with -DSHM if you want to compile in support
  68.  * for the MIT Shared Memory extension.  If enabled, when you use an Ximage
  69.  * for the back buffer in double buffered mode, the "swap" operation will
  70.  * be faster.  You must also link with -lXext.
  71.  *
  72.  */
  73.  
  74.  
  75. #include <assert.h>
  76. #include <stdio.h>
  77. #include <stdlib.h>
  78. #include <string.h>
  79. #include <X11/Xlib.h>
  80. #include <X11/Xutil.h>
  81. #ifdef SHM
  82. #  include <sys/ipc.h>
  83. #  include <sys/shm.h>
  84. #  include <X11/extensions/XShm.h>
  85. #endif
  86. #include "GL/xmesa.h"
  87. #include "xmesaP.h"
  88. #include "context.h"
  89. /*#include "dd.h"*/
  90. #include "macros.h"
  91. #include "xform.h"
  92.  
  93. XMesaContext XMesa = NULL;
  94.  
  95.  
  96.  
  97.  
  98. /**********************************************************************/
  99. /*****                      Private Functions                     *****/
  100. /**********************************************************************/
  101.  
  102.  
  103. /*
  104.  * X/Mesa Error reporting function:
  105.  */
  106. static void error( const char *msg )
  107. {
  108.    fprintf( stderr, "X/Mesa error: %s\n", msg );
  109. }
  110.  
  111.  
  112. /*
  113.  * Return the host's byte order as LSBFirst or MSBFirst ala X.
  114.  */
  115. static int host_byte_order( void )
  116. {
  117.    int i = 1;
  118.    char *cptr = (char *) &i;
  119.    return (*cptr==1) ? LSBFirst : MSBFirst;
  120. }
  121.  
  122.  
  123.  
  124. /*
  125.  * Error handling.
  126.  */
  127. static int mesaXErrorFlag = 0;
  128.  
  129. static int mesaHandleXError( Display *dpy, XErrorEvent *event )
  130. {
  131.     mesaXErrorFlag = 1;
  132.     return 0;
  133. }
  134.  
  135.  
  136. /*
  137.  * Check if the X Shared Memory extension is available.
  138.  * Return:  0 = not available
  139.  *          1 = shared XImage support available
  140.  *          2 = shared Pixmap support available also
  141.  */
  142. static int check_for_xshm( Display *display )
  143. {
  144. #ifdef SHM
  145.    int major, minor, ignore;
  146.    Bool pixmaps;
  147.  
  148.    if (XQueryExtension( display, "MIT-SHM", &ignore, &ignore, &ignore )) {
  149.       if (XShmQueryVersion( display, &major, &minor, &pixmaps )==True) {
  150.      return (pixmaps==True) ? 2 : 1;
  151.       }
  152.       else {
  153.      return 0;
  154.       }
  155.    }
  156.    else {
  157.       return 0;
  158.    }
  159. #else
  160.    /* Can't compile XSHM support */
  161.    return 0;
  162. #endif
  163. }
  164.  
  165.  
  166. /*
  167.  * Allocate a shared memory XImage back buffer for the given context.
  168.  * Return:  GL_TRUE if success, GL_FALSE if error
  169.  */
  170. static GLboolean alloc_shm_back_buffer( XMesaContext c )
  171. {
  172. #ifdef SHM
  173.    /*
  174.     * We have to do a _lot_ of error checking here to be sure we can
  175.     * really use the XSHM extension.  It seems different servers trigger
  176.     * errors at different points if the extension won't work.  Therefore
  177.     * we have to be very careful...
  178.     */
  179.    GC gc;
  180.    c->backimage = XShmCreateImage( c->display, c->visual, c->depth,
  181.                    ZPixmap, NULL, &c->shminfo,
  182.                    c->width, c->height );
  183.    if (c->backimage == NULL) {
  184.       error( "alloc_back_buffer: Shared memory error (XShmCreateImage), disabling." );
  185.       c->shm = 0;
  186.       return GL_FALSE;
  187.    }
  188.  
  189.    c->shminfo.shmid = shmget( IPC_PRIVATE, c->backimage->bytes_per_line
  190.                  * c->backimage->height, IPC_CREAT|0777 );
  191.    if (c->shminfo.shmid < 0) {
  192.       perror("alloc_back_buffer");
  193.       XDestroyImage( c->backimage );
  194.       c->backimage = NULL;
  195.       error( "alloc_back_buffer: Shared memory error (shmget), disabling." );
  196.       c->shm = 0;
  197.       return GL_FALSE;
  198.    }
  199.  
  200.    c->shminfo.shmaddr = c->backimage->data
  201.                       = (char*)shmat( c->shminfo.shmid, 0, 0 );
  202.    if (c->shminfo.shmaddr == (char *) -1) {
  203.       perror("alloc_back_buffer");
  204.       XDestroyImage( c->backimage );
  205.       c->backimage = NULL;
  206.       error("alloc_back_buffer: Shared memory error (shmat), disabling.");
  207.       c->shm = 0;
  208.       return GL_FALSE;
  209.    }
  210.  
  211.    c->shminfo.readOnly = False;
  212.    mesaXErrorFlag = 0;
  213.    XSetErrorHandler( mesaHandleXError );
  214.    /* This may trigger the X protocol error we're ready to catch: */
  215.    XShmAttach( c->display, &c->shminfo );
  216.    XSync( c->display, False );
  217.  
  218.    if (mesaXErrorFlag) {
  219.       /* we are on a remote display, this error is normal, don't print it */
  220.       XFlush( c->display );
  221.       mesaXErrorFlag = 0;
  222.       XDestroyImage( c->backimage );
  223.       shmdt( c->shminfo.shmaddr );
  224.       shmctl( c->shminfo.shmid, IPC_RMID, 0 );
  225.       c->backimage = NULL;
  226.       c->shm = 0;
  227.       return GL_FALSE;
  228.    }
  229.  
  230.    shmctl( c->shminfo.shmid, IPC_RMID, 0 ); /* nobody else needs it */
  231.  
  232.    /* Finally, try an XShmPutImage to be really sure the extension works */
  233.    gc = XCreateGC( c->display, c->frontbuffer, 0, NULL );
  234.    XShmPutImage( c->display, c->frontbuffer, gc,
  235.          c->backimage, 0, 0, 0, 0, 1, 1 /*one pixel*/, False );
  236.    XSync( c->display, False );
  237.    XFreeGC( c->display, gc );
  238.    XSetErrorHandler( NULL );
  239.    if (mesaXErrorFlag) {
  240.       XFlush( c->display );
  241.       mesaXErrorFlag = 0;
  242.       XDestroyImage( c->backimage );
  243.       shmdt( c->shminfo.shmaddr );
  244.       shmctl( c->shminfo.shmid, IPC_RMID, 0 );
  245.       c->backimage = NULL;
  246.       c->shm = 0;
  247.       return GL_FALSE;
  248.    }
  249.  
  250.    return GL_TRUE;
  251. #else
  252.    /* Can't compile XSHM support */
  253.    return GL_FALSE;
  254. #endif
  255. }
  256.  
  257.  
  258.  
  259. /*
  260.  * Setup an off-screen pixmap or Ximage to use as the back buffer.
  261.  * Input:  c - the X/Mesa context.
  262.  */
  263. void xmesa_alloc_back_buffer( XMesaContext c )
  264. {
  265.    if (c->db_state==BACK_XIMAGE) {
  266.       char *img;
  267.  
  268.       /* Deallocate the old backimage, if any */
  269.       if (c->backimage) {
  270. #ifdef SHM
  271.      if (c->shm) {
  272.         XShmDetach( c->display, &c->shminfo );
  273.         XDestroyImage( c->backimage );
  274.         shmdt( c->shminfo.shmaddr );
  275.      }
  276.      else
  277. #endif
  278.        XDestroyImage( c->backimage );
  279.      c->backimage = NULL;
  280.       }
  281.  
  282.       /* Allocate new back buffer */
  283.       if (c->shm==0 || alloc_shm_back_buffer(c)==GL_FALSE) {
  284.      /* Allocate a regular XImage for the back buffer. */
  285.      /* TODO: this number of bytes computation is a hack! */
  286.      img = (char *) malloc( c->width * c->height * 4 );
  287.      c->backimage = XCreateImage( c->display, c->visual, c->depth,
  288.                       ZPixmap, 0,   /* format, offset */
  289.                       img, c->width, c->height,
  290.                       8, 0 );  /* pad, bytes_per_line */
  291.      if (!c->backimage) {
  292.         /* TODO: more related error checks are needed throughout xmesa.c */
  293.         error("alloc_back_buffer: XCreateImage failed.");
  294.      }
  295.       }
  296.       c->backpixmap = None;
  297.    }
  298.    else if (c->db_state==BACK_PIXMAP) {
  299.       Pixmap old_pixmap = c->backpixmap;
  300.       /* Free the old back pixmap */
  301.       if (c->backpixmap) {
  302.      XFreePixmap( c->display, c->backpixmap );
  303.       }
  304.       /* Allocate new back pixmap */
  305.       c->backpixmap = XCreatePixmap( c->display, c->frontbuffer,
  306.                      c->width, c->height, c->depth );
  307.       c->backimage = NULL;
  308.       /* update other references to backpixmap */
  309.       if (c->buffer==old_pixmap) {
  310.      c->buffer = c->backpixmap;
  311.       }
  312.    }
  313. }
  314.  
  315.  
  316.  
  317. /*
  318.  * Return the width and height of the given drawable.
  319.  */
  320. static void get_drawable_size( Display *dpy, Drawable d,
  321.                    unsigned int *width, unsigned int *height )
  322. {
  323.    Window root;
  324.    int x, y;
  325.    unsigned int bw, depth;
  326.  
  327.    XGetGeometry( dpy, d, &root, &x, &y, width, height, &bw, &depth );
  328. }
  329.  
  330.  
  331.  
  332.  
  333. static int setup_grayscale( XMesaContext c, Window window )
  334. {
  335.    int r, g, b, i;
  336.    int colorsfailed = 0;
  337.    XColor xcol;
  338.    XColor *ctable = NULL;
  339.    Colormap cmap;
  340.    XWindowAttributes attr;
  341.  
  342.    assert( c->depth>=4 && c->depth<=16 );
  343.  
  344.    /* Need to know the colormap in this case */
  345.    XGetWindowAttributes( c->display, window, &attr );
  346.    cmap = attr.colormap;
  347.  
  348.    /* This is a hack for GLUT: pre-allocate the gray needed for pop-up menus */
  349.    xcol.red = xcol.green = xcol.blue = 0xaa00;
  350.    XAllocColor( c->display, cmap, &xcol );
  351.  
  352. #define distance2(r1,g1,b1,r2,g2,b2)  ( ((r2)-(r1)) * ((r2)-(r1)) + \
  353.     ((g2)-(g1)) * ((g2)-(g1)) + ((b2)-(b1)) * ((b2)-(b1)) )
  354.  
  355.    /* Allocate 256 shades of gray */
  356.    for (g=0;g<256;g++) {
  357.       xcol.red = xcol.green = xcol.blue  = (g << 8) | g;
  358.       if (!XAllocColor(c->display, cmap, &xcol)) {
  359.          /* Search for best match (contributed by Michael Pichler) */
  360.          int p, bestmatch;
  361.          double dist, mindist;  /* 3*2^16^2 exceeds long int precision */
  362.          int cmap_size = c->visual->map_entries;
  363.  
  364.          /* query whole colormap if not yet done */
  365.          if (!ctable) {
  366.             ctable = (XColor *) malloc( cmap_size * sizeof(XColor) );
  367.             for (p = 0;  p < cmap_size;  p++)
  368.               ctable[p].pixel = p;
  369.             XQueryColors (c->display, cmap, ctable, cmap_size);
  370.          }
  371.  
  372.          /* find best match */
  373.          mindist = 0.0;
  374.          bestmatch = -1;
  375.          p = cmap_size;
  376.          while (p--) {
  377.             int mapgray;
  378.             mapgray = (ctable[p].red + ctable[p].green + ctable[p].blue) / 3U;
  379.             dist = ABS( mapgray - ((g << 8) | g) );
  380.             if (bestmatch < 0 || dist < mindist)
  381.               mindist = dist, bestmatch = p;
  382.          }
  383.          xcol.pixel = bestmatch;
  384.          colorsfailed++;
  385.       }
  386.       c->color_table[g] = xcol.pixel;
  387.       c->red_table[xcol.pixel]   = g * 30 / 100;
  388.       c->green_table[xcol.pixel] = g * 59 / 100;
  389.       c->blue_table[xcol.pixel]  = g * 11 / 100;
  390.    }
  391.  
  392. #undef distance2
  393.  
  394.    if (ctable) {
  395.       free(ctable);
  396.    }
  397.  
  398.    if (colorsfailed) {
  399.       fprintf( stderr,
  400.                "Note: %d out of 256 needed colors do not match exactly.\n",
  401.            colorsfailed, 256 );
  402.    }
  403.  
  404. #define WEIGHT
  405. #ifdef WEIGHT
  406.    c->rmult = 30 * 255 / 100;
  407.    c->gmult = 59 * 255 / 100;
  408.    c->bmult = 11 * 255 / 100;
  409. #else
  410.    c->rmult = 255/3;
  411.    c->gmult = 255/3;
  412.    c->bmult = 255/3;
  413. #endif
  414.    c->amult = 255;
  415.    c->dithered_pf = PF_GRAYSCALE;
  416.    c->undithered_pf = PF_GRAYSCALE;
  417.    c->pixel = c->color_table[255];      /* white */
  418.    c->clearpixel = c->color_table[0];   /* black */
  419.  
  420.    return 1;
  421. }
  422.  
  423.  
  424.  
  425. /*
  426.  * Setup RGB rending for a window with a PseudoColor, StaticColor,
  427.  * GrayScale or StaticGray visual.  We try to allocate a palette of 225
  428.  * colors (5 red, 9 green, 5 blue) and dither to approximate a 24-bit RGB
  429.  * color.  While this function was originally designed just for 8-bit
  430.  * visuals, it has also proven to work from 4-bit up to 16-bit visuals.
  431.  * The fact that this method works for gray scale displays depends on
  432.  * XAllocColor allocating a good gray to approximate an RGB color.
  433.  * Dithering code contributed by Bob Mercier.
  434.  */
  435. static int setup_dithered_color( XMesaContext c, Window window )
  436. {
  437.    int r, g, b, i;
  438.    int colorsfailed = 0;
  439.    XColor xcol;
  440.    XColor *allcolors = NULL, *acptr;
  441.    Colormap cmap;
  442.    XWindowAttributes attr;
  443.  
  444.    assert( c->depth>=4 && c->depth<=16 );
  445.  
  446.    /* Need to know the colormap in this case */
  447.    XGetWindowAttributes( c->display, window, &attr );
  448.    cmap = attr.colormap;
  449.  
  450.    /* This is a hack for GLUT: pre-allocate the gray needed for pop-up menus */
  451.    xcol.red = xcol.green = xcol.blue = 0xaa00;
  452.    XAllocColor( c->display, cmap, &xcol );
  453.  
  454. #define distance2(r1,g1,b1,r2,g2,b2)  ( ((r2)-(r1)) * ((r2)-(r1)) + \
  455.     ((g2)-(g1)) * ((g2)-(g1)) + ((b2)-(b1)) * ((b2)-(b1)) )
  456.  
  457.    /* Allocate X colors and initialize color_table[], red_table[], etc */
  458.    for (r = 0; r < _R; r++) {
  459.       for (g = 0; g < _G; g++) {
  460.      for (b = 0; b < _B; b++) {
  461.         xcol.red   = r * 65535 / (_R-1);
  462.         xcol.green = g * 65535 / (_G-1);
  463.         xcol.blue  = b * 65535 / (_B-1);
  464.         if (!XAllocColor(c->display, cmap, &xcol)) {
  465.            /* Search for best match (contributed by Michael Pichler) */
  466.            int p, bestmatch;
  467.            double dist, mindist;  /* 3*2^16^2 exceeds long int precision */
  468.            int cmap_size = c->visual->map_entries;
  469.  
  470.            /* query whole colormap if not yet done */
  471.            if (!allcolors) {
  472.           allcolors = (XColor *) malloc( cmap_size * sizeof(XColor) );
  473.           for (p = 0;  p < cmap_size;  p++)
  474.             allcolors[p].pixel = p;
  475.           XQueryColors (c->display, cmap, allcolors, cmap_size);
  476.            }
  477.  
  478.            /* find best match */
  479.            mindist = 0.0;
  480.            bestmatch = -1;
  481.            p = cmap_size;
  482.            while (p--) {
  483.           acptr = allcolors + p;
  484.           dist = distance2( (double)xcol.red, (double)xcol.green,
  485.                     (double)xcol.blue, (double)acptr->red,
  486.                     (double)acptr->green, (double)acptr->blue);
  487.           if (bestmatch < 0 || dist < mindist)
  488.              mindist = dist, bestmatch = p;
  489.            }
  490.            xcol.pixel = bestmatch;
  491.            colorsfailed++;
  492.         }
  493.         i = _MIX( r, g, b );
  494.         c->color_table[i] = xcol.pixel;
  495.         c->red_table[xcol.pixel]   = r * 255 / (_R-1);
  496.         c->green_table[xcol.pixel] = g * 255 / (_G-1);
  497.         c->blue_table[xcol.pixel]  = b * 255 / (_B-1);
  498.      }
  499.       }
  500.    }
  501.  
  502. #undef distance2
  503.  
  504.    if (allcolors) {
  505.       free(allcolors);
  506.    }
  507.  
  508.    if (colorsfailed) {
  509.       fprintf( stderr,
  510.                "Note: %d out of %d needed colors do not match exactly.\n",
  511.            colorsfailed, _R*_G*_B );
  512.    }
  513.  
  514.    c->rmult = 255;
  515.    c->gmult = 255;
  516.    c->bmult = 255;
  517.    c->amult = 255;
  518.    c->dithered_pf = PF_DITHER;
  519.    c->undithered_pf = PF_LOOKUP;
  520.    c->pixel = c->color_table[_MIX(_R-1,_G-1,_B-1)];  /* white */
  521.    c->clearpixel = c->color_table[_MIX(0,0,0)];      /* black */
  522.  
  523.    return 1;
  524. }
  525.  
  526.  
  527.  
  528. /*
  529.  * Setup RGB rending for a window with a True/DirectColor visual.
  530.  */
  531. static int setup_truecolor( XMesaContext c, Window window )
  532. {
  533.    unsigned long rmask, gmask, bmask;
  534.  
  535.    /*
  536.     * Use the red, green, and blue mask values in the visual structure
  537.     * to compute the multiplier and shift values for converting RGB
  538.     * triplets from floats in [0,1] to packed pixel values.
  539.     */
  540.  
  541.    /* Red */
  542.    c->rshift = 0;
  543.    rmask = c->visual->red_mask;
  544.    while ((rmask & 1)==0) {
  545.       c->rshift++;
  546.       rmask = rmask >> 1;
  547.    }
  548.    c->rmult = (GLint) rmask;
  549.  
  550.    /* Green */
  551.    c->gshift = 0;
  552.    gmask = c->visual->green_mask;
  553.    while ((gmask & 1)==0) {
  554.       c->gshift++;
  555.       gmask = gmask >> 1;
  556.    }
  557.    c->gmult = (GLint) gmask;
  558.  
  559.    /* Blue */
  560.    c->bshift = 0;
  561.    bmask = c->visual->blue_mask;
  562.    while ((bmask & 1)==0) {
  563.       c->bshift++;
  564.       bmask = bmask >> 1;
  565.    }
  566.    c->bmult = (GLint) bmask;
  567.  
  568.    /* Alpha */
  569.    c->ashift = 24;
  570.    c->amult = 255;
  571.  
  572.    if (host_byte_order() != ImageByteOrder(c->display)) {
  573.       /* Must reverse order of bytes in back buffer's XImage before sending */
  574.       /* to server. */
  575.       c->swapbytes = GL_TRUE;
  576.    }
  577.  
  578.    if (c->rshift==0 && c->gshift==8 && c->bshift==16
  579.        && ImageByteOrder(c->display)==MSBFirst) {
  580.       /* a common case */
  581.       c->undithered_pf = c->dithered_pf = PF_8A8B8G8R;
  582.       c->pixel = 0xffffffff;  /* white */
  583.       c->clearpixel = 0x0;    /* black */
  584.    }
  585.    else if (  c->rshift==5 && c->gshift==2 && c->bshift==0
  586.            && XInternAtom(c->display, "_HP_RGB_SMOOTH_MAP_LIST", True)) {
  587.       /* HP Color Recovery
  588.        * To work properly, the atom _HP_RGB_SMOOTH_MAP_LIST must be defined
  589.        * on the root window AND the colormap obtainable by XGetRGBColormaps
  590.        * for that atom must be set on the window.  (see also tkInitWindow)
  591.        * If that colormap is not set, the output will look stripy.
  592.        */
  593.       c->undithered_pf = PF_TRUECOLOR;
  594.       c->dithered_pf = PF_HPCR;
  595.       c->pixel = c->visual->red_mask | c->visual->green_mask
  596.                | c->visual->blue_mask;  /* white */
  597.       c->clearpixel = 0x0;    /* black */
  598.       c->rmult = 255;
  599.       c->gmult = 255;
  600.       c->bmult = 255;
  601.       c->amult = 255;
  602.    }
  603.    else if (c->depth==8) {
  604.       /* dither if 8-bit */
  605.       setup_dithered_color( c, window );
  606.    }
  607.    else {
  608.       /* general case */
  609.       c->undithered_pf = c->dithered_pf = PF_TRUECOLOR;
  610.       c->pixel = c->visual->red_mask | c->visual->green_mask
  611.              | c->visual->blue_mask;  /* white */
  612.       c->clearpixel = 0x0;    /* black */
  613.    }
  614.  
  615.    return 1;
  616. }
  617.  
  618.  
  619.  
  620. /*
  621.  * Setup RGB rending for a window with a monochrome visual.
  622.  */
  623. static int setup_monochrome( XMesaContext c )
  624. {
  625.    /* Simulate RGB in monochrome */
  626.    c->rmult = 255;
  627.    c->gmult = 255;
  628.    c->bmult = 255;
  629.    c->amult = 255;
  630.    c->dithered_pf = c->undithered_pf = PF_1BIT;
  631.  
  632.    /* is it OK to hardcode these values? */
  633.    c->pixel = 1;       /* white */
  634.    c->clearpixel = 0;  /* black */
  635.  
  636.    return 1;
  637. }
  638.  
  639.  
  640. extern void init_gamma_tables( struct gl_context *c );
  641.  
  642.  
  643. /*
  644.  * When a context is "made current" for the first time, we can finally
  645.  * finish initializing the context.
  646.  * Input:  c - the XMesaContext to initialize
  647.  *         window - the window we're rendering into if RGB mode & PseudoColor
  648.  *
  649.  */
  650. static GLboolean initialize_context( XMesaContext c, Window window )
  651. {
  652.    XGCValues gcvalues;
  653.  
  654.    assert( c->initialized==GL_FALSE );
  655.  
  656.    if (c->rgb_flag==GL_FALSE) {
  657.       /* COLOR-INDEXED WINDOW:
  658.        * Even if the visual is TrueColor or DirectColor we treat it as
  659.        * being color indexed.  This is weird but might be useful to someone.
  660.        */
  661.       c->dithered_pf = c->undithered_pf = PF_INDEX;
  662.       c->pixel = 1;
  663.       c->clearpixel = 0;
  664.       c->rmult = c->gmult = c->bmult = c->amult = 0;
  665.    }
  666.    else {
  667.       /* RGB WINDOW:
  668.        * If the visual is TrueColor or DirectColor we're all set.  Other-
  669.        * wise, we simulate RGB mode using a color-mapped window.
  670.        */
  671.       int xclass;
  672. #if defined(__cplusplus) || defined(c_plusplus)
  673.       xclass = c->visual->c_class;
  674. #else
  675.       xclass = c->visual->class;
  676. #endif
  677.       if (xclass==TrueColor || xclass==DirectColor) {
  678.      (void) setup_truecolor( c, window );
  679.       }
  680.       else if (xclass==StaticGray && c->depth==1) {
  681.      (void) setup_monochrome( c );
  682.       }
  683.       else if (xclass==GrayScale || xclass==StaticGray) {
  684. /*NEW*/         (void) setup_grayscale( c, window );
  685.       }
  686.       else if ((xclass==PseudoColor || xclass==StaticColor)
  687.                && c->depth>=4 && c->depth<=16) {
  688.      (void) setup_dithered_color( c, window );
  689.       }
  690.       else {
  691.      error("XMesaCreateContext: can't simulate RGB mode with given visual.");
  692.      return GL_FALSE;
  693.       }
  694.    }
  695.  
  696.    /* Now allocate the GL context */
  697.    c->gl_ctx = gl_new_context( c->rgb_flag,
  698.                                (GLfloat) c->rmult,
  699.                                (GLfloat) c->gmult,
  700.                                (GLfloat) c->bmult,
  701.                                (GLfloat) c->amult,
  702.                                c->db_state ? GL_TRUE : GL_FALSE,
  703.                                c->share_list ? c->share_list->gl_ctx : NULL );
  704.  
  705.    /* Dithering is enabled by default */
  706.    c->pixelformat = c->dithered_pf;
  707.  
  708.    get_drawable_size( c->display, window, &c->width, &c->height );
  709.  
  710.    if (c->db_state) {
  711.       /* Double buffered */
  712.       xmesa_alloc_back_buffer( c );
  713.       if (c->db_state==BACK_PIXMAP) {
  714.          c->buffer = c->backpixmap;
  715.       }
  716.       else {
  717.          c->buffer = XIMAGE;
  718.       }
  719.    }
  720.    else {
  721.       /* Single Buffered */
  722.       c->buffer = c->frontbuffer;
  723.    }
  724.  
  725.    /* X11 graphics context */
  726.    c->gc1 = XCreateGC( c->display, window, 0, NULL );
  727.    XSetForeground( c->display, c->gc1, c->pixel );
  728.    XSetBackground( c->display, c->gc1, c->pixel );
  729.    XSetFunction( c->display, c->gc1, GXcopy );
  730.    c->gc2 = XCreateGC( c->display, window, 0, NULL );
  731.    XSetForeground( c->display, c->gc2, c->pixel );
  732.    XSetBackground( c->display, c->gc2, c->pixel );
  733.    XSetFunction( c->display, c->gc2, GXcopy );
  734.    /*
  735.     * Don't generate Graphics Expose/NoExpose events in swapbuffers().
  736.     * Patch contributed by Michael Pichler May 15, 1995.
  737.     */
  738.    gcvalues.graphics_exposures = False;
  739.    c->cleargc = XCreateGC( c->display, window, GCGraphicsExposures, &gcvalues);
  740.    XSetForeground( c->display, c->cleargc, c->clearpixel );
  741.    XSetBackground( c->display, c->cleargc, c->clearpixel );
  742.    XSetFunction( c->display, c->cleargc, GXcopy );
  743.  
  744.    /* Initialize the row buffer XImage for use in write_color_span() */
  745.    c->rowimage = XCreateImage( c->display, c->visual, c->depth,
  746.                                ZPixmap, 0,                  /*format, offset*/
  747.                                (char*) malloc(MAX_WIDTH*4), /*data*/
  748.                                MAX_WIDTH, 1,                /*width, height*/
  749.                                32,                          /*bitmap_pad*/
  750.                                0                         /*bytes_per_line*/ );
  751.  
  752.  
  753.    c->initialized = GL_TRUE;
  754.  
  755.    return GL_TRUE;
  756. }
  757.  
  758.  
  759.  
  760.  
  761. /**********************************************************************/
  762. /*****                       Public Functions                     *****/
  763. /**********************************************************************/
  764.  
  765.  
  766. /*
  767.  * Create a new XMesaContext for rendering into an X11 window.
  768.  *
  769.  * Input:  display - X11 display
  770.  *         visinfo - X11 VisualInfo describing the colorbuffer we'll use
  771.  *         rgb_flag - GL_TRUE = RGB mode,
  772.  *                    GL_FALSE = color index mode
  773.  *         db_flag - GL_TRUE = double-buffered,
  774.  *                   GL_FALSE = single buffered
  775.  *         ximage_flag - GL_TRUE = use an XImage for back buffer,
  776.  *                       GL_FALSE = use an off-screen pixmap for back buffer
  777.  *         share_list - another XMesaContext with which to share display
  778.  *                      lists or NULL if no sharing is wanted.
  779.  * Return:  an XMesaContext or NULL if error.
  780.  */
  781. XMesaContext XMesaCreateContext( Display *display,
  782.                  XVisualInfo *visinfo,
  783.                  GLboolean rgb_flag,
  784.                  GLboolean db_flag,
  785.                  GLboolean ximage_flag,
  786.                  XMesaContext share_list )
  787. {
  788.    XMesaContext c;
  789.  
  790.    /* allocate xmesa_context struct initialized to zeros */
  791.    c = (struct xmesa_context *) calloc( 1, sizeof(struct xmesa_context) );
  792.    if (!c) {
  793.       return NULL;
  794.    }
  795.  
  796.    c->rgb_flag = rgb_flag;
  797.    c->share_list = share_list;
  798.  
  799.    /* X stuff */
  800.    c->display = display;
  801.    c->visual = visinfo->visual;
  802.    c->depth = visinfo->depth;
  803.    c->shm = check_for_xshm( display );
  804.    c->swapbytes = GL_FALSE;
  805.  
  806.    /* Double buffering configuration */
  807.    if (db_flag) {
  808.       if (ximage_flag) {
  809.      c->db_state = BACK_XIMAGE;
  810.       }
  811.       else {
  812.      c->db_state = BACK_PIXMAP;
  813.       }
  814.    }
  815.    else {
  816.       c->db_state = 0;
  817.    }
  818.  
  819.    /*XSynchronize( display, 1 );*/    /* This makes debugging X easier */
  820.  
  821.    return c;
  822. }
  823.  
  824.  
  825.  
  826.  
  827. void XMesaDestroyContext( XMesaContext c )
  828. {
  829.    if (c->gl_ctx)  gl_destroy_context( c->gl_ctx );
  830.  
  831.    if (c->gc1)  XFreeGC( c->display, c->gc1 );
  832.    if (c->gc2)  XFreeGC( c->display, c->gc2 );
  833.    if (c->cleargc)  XFreeGC( c->display, c->cleargc );
  834.  
  835.    if (c->backimage) {
  836. #ifdef SHM
  837.        if (c->shm) {
  838.        XShmDetach( c->display, &c->shminfo );
  839.        XDestroyImage( c->backimage );
  840.        shmdt( c->shminfo.shmaddr );
  841.        }
  842.        else
  843. #endif
  844.        XDestroyImage( c->backimage );
  845.    }
  846.    if (c->backpixmap) {
  847.       XFreePixmap( c->display, c->backpixmap );
  848.    }
  849.    if (c->rowimage) {
  850.       free( c->rowimage->data );
  851.       c->rowimage->data = NULL;
  852.       XDestroyImage( c->rowimage );
  853.    }
  854.    free( c );
  855. }
  856.  
  857.  
  858.  
  859. /*
  860.  * Bind an X/Mesa context to an X window.
  861.  */
  862. GLboolean XMesaBindWindow( XMesaContext c, Window w )
  863. {
  864.    if (c->buffer==c->frontbuffer) {
  865.       c->buffer = w;
  866.    }
  867.    c->frontbuffer = w;
  868.    if (!c->initialized) {
  869.       if (!initialize_context( c, w )) {
  870.      return GL_FALSE;
  871.       }
  872.    }
  873.    return GL_TRUE;
  874. }
  875.  
  876.  
  877.  
  878. /*
  879.  * Bind an X/Mesa context to an X pixmap.
  880.  */
  881. GLboolean XMesaBindPixmap( XMesaContext c, Pixmap p )
  882. {
  883.    if (c->buffer==c->frontbuffer) {
  884.       c->buffer = p;
  885.    }
  886.    c->frontbuffer = p;
  887.  
  888.    if (!c->initialized) {
  889.       int xclass;
  890. #if defined(__cplusplus) || defined(c_plusplus)
  891.       xclass = c->visual->c_class;
  892. #else
  893.       xclass = c->visual->class;
  894. #endif
  895.       if (c->rgb_flag && xclass==PseudoColor) {
  896.      /* Error, there isn't enough information carried in a pixmap */
  897.      /* to initialize the context.  Specifically, we need to know */
  898.      /* the colormap at this point for this configuration. */
  899.      return GL_FALSE;
  900.       }
  901.       if (!initialize_context( c, p )) {
  902.      return GL_FALSE;
  903.       }
  904.    }
  905.    return GL_TRUE;
  906. }
  907.  
  908.  
  909.  
  910. GLboolean XMesaMakeCurrent( XMesaContext c )
  911. {
  912.    if (c) {
  913.       if (!c->initialized) {
  914.          return GL_FALSE;
  915.       }
  916.       gl_set_context( c->gl_ctx );
  917.       XMesa = c;
  918.  
  919.       xmesa_setup_DD_pointers();
  920.  
  921.       if (XMesa->gl_ctx->Viewport.Width==0) {
  922.      /* initialize viewport to window size */
  923.      gl_viewport( 0, 0, XMesa->width, XMesa->height );
  924.      CC.Scissor.Width = XMesa->width;
  925.      CC.Scissor.Height = XMesa->height;
  926.       }
  927.    }
  928.    else {
  929.       /* Detach */
  930.       XMesa = NULL;
  931.    }
  932.    return GL_TRUE;
  933. }
  934.  
  935.  
  936.  
  937. XMesaContext XMesaGetCurrentContext( void )
  938. {
  939.    return XMesa;
  940. }
  941.  
  942.  
  943.  
  944. /*
  945.  * Perform byte swapping on an XImage if the host and server use a different
  946.  * byte ordering.
  947.  */
  948. static void swap_image_data( XImage *img )
  949. {
  950.    register GLuint i, j, *ptr4, p;
  951.  
  952.    if (img->bits_per_pixel==32) {
  953.       for (i=0;i<img->height;i++) {
  954.          ptr4 = (GLuint *) (img->data + i*img->bytes_per_line);
  955.          for (j=0;j<img->width;j++) {
  956.             p = ptr4[j];
  957.             ptr4[j] = ((p & 0xff000000) >> 24)
  958.                     | ((p & 0x00ff0000) >> 8)
  959.                     | ((p & 0x0000ff00) << 8)
  960.                     | ((p & 0x000000ff) << 24);
  961.          }
  962.       }
  963.    }
  964.    /* 12-bit??? */
  965. }
  966.  
  967.  
  968. /*
  969.  * Copy the back buffer to the front buffer.  If there's no back buffer
  970.  * this is a no-op.
  971.  */
  972. void XMesaSwapBuffers( void )
  973. {
  974.    if (XMesa->db_state) {
  975.       if (XMesa->backimage) {
  976.      /* Copy Ximage from host's memory to server's window */
  977. #ifdef SHM
  978.      if (XMesa->shm) {
  979.         XShmPutImage( XMesa->display, XMesa->frontbuffer,
  980.               XMesa->cleargc,
  981.               XMesa->backimage, 0, 0,
  982.               0, 0, XMesa->width, XMesa->height, False );
  983.         /* wait for finished event??? */
  984.      }
  985.      else
  986. #endif
  987.          {
  988.             if (XMesa->swapbytes) {
  989.                swap_image_data( XMesa->backimage );
  990.             }
  991.             XPutImage( XMesa->display, XMesa->frontbuffer,
  992.                        XMesa->cleargc,
  993.                        XMesa->backimage, 0, 0,
  994.                        0, 0, XMesa->width, XMesa->height );
  995.          }
  996.       }
  997.       else {
  998.      /* Copy pixmap to window on server */
  999.      XCopyArea( XMesa->display,
  1000.             XMesa->backpixmap,   /* source drawable */
  1001.             XMesa->frontbuffer,  /* dest. drawable */
  1002.             XMesa->cleargc,
  1003.             0, 0, XMesa->width, XMesa->height,  /* source region */
  1004.             0, 0                 /* dest region */
  1005.            );
  1006.       }
  1007.    }
  1008.  
  1009.    XSync( XMesa->display, False );
  1010. }
  1011.  
  1012.  
  1013.  
  1014. /*
  1015.  * Return a pointer to the XMesa backbuffer Pixmap or XImage.  This function
  1016.  * is a way to get "under the hood" of X/Mesa so one can manipulate the
  1017.  * back buffer directly.
  1018.  * Output:  pixmap - pointer to back buffer's Pixmap, or 0
  1019.  *          ximage - pointer to back buffer's XImage, or NULL
  1020.  * Return:  GL_TRUE = context is double buffered
  1021.  *          GL_FALSE = context is single buffered
  1022.  */
  1023. GLboolean XMesaGetBackBuffer( Pixmap *pixmap, XImage **ximage )
  1024. {
  1025.    if (XMesa->db_state) {
  1026.       if (pixmap)  *pixmap = XMesa->backpixmap;
  1027.       if (ximage)  *ximage = XMesa->backimage;
  1028.       return GL_TRUE;
  1029.    }
  1030.    else {
  1031.       *pixmap = 0;
  1032.       *ximage = NULL;
  1033.       return GL_FALSE;
  1034.    }
  1035. }
  1036.  
  1037.  
  1038.